home *** CD-ROM | disk | FTP | other *** search
- Subject: v18i047: SC spreadsheet, version 6.1, Part03/04
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Robert Bond <sequent!rgb@uunet.uu.net>
- Posting-number: Volume 18, Issue 47
- Archive-name: sc6.1/part03
-
- # This is a shell archive. Remove anything before this line
- # then unpack it by saving it in a file and typing "sh file"
- # (Files unpacked will be owned by you and have default permissions).
- # This archive contains the following files:
- # ./gram.y
- # ./interp.c
- # ./crypt.c
- #
- if `test ! -s ./gram.y`
- then
- echo "Extracting ./gram.y"
- cat > ./gram.y << '\SHAR\EOF\'
- /* SC A Spreadsheet Calculator
- * Command and expression parser
- *
- * original by James Gosling, September 1982
- * modified by Mark Weiser and Bruce Israel,
- * University of Maryland
- *
- * more mods Robert Bond 12/86
- *
- * More mods by Alan Silverstein, 3/88, see list of changes.
- *
- * $Revision: 6.1 $
- */
-
-
-
- %{
- #include <curses.h>
- #include "sc.h"
-
- #define ENULL (struct enode *)0
-
- char *strcpy();
- %}
-
- %union {
- int ival;
- double fval;
- struct ent_ptr ent;
- struct enode *enode;
- char *sval;
- struct range_s rval;
- }
-
- %type <ent> var
- %type <fval> num
- %type <rval> range
- %type <rval> var_or_range
- %type <sval> strarg
- %type <enode> e term expr_list
- %token <sval> STRING
- %token <ival> NUMBER
- %token <fval> FNUMBER
- %token <rval> RANGE
- %token <rval> VAR
- %token <sval> WORD
- %token <ival> COL
- %token S_FORMAT
- %token S_LABEL
- %token S_LEFTSTRING
- %token S_RIGHTSTRING
- %token S_GET
- %token S_PUT
- %token S_MERGE
- %token S_LET
- %token S_WRITE
- %token S_TBL
- %token S_COPY
- %token S_SHOW
- %token S_ERASE
- %token S_FILL
- %token S_GOTO
- %token S_DEFINE
- %token S_UNDEFINE
- %token S_VALUE
- %token S_MDIR
- %token S_HIDE
- %token S_SET
-
- %token K_FIXED
- %token K_SUM
- %token K_PROD
- %token K_AVG
- %token K_STDDEV
- %token K_ACOS
- %token K_ASIN
- %token K_ATAN
- %token K_ATAN2
- %token K_CEIL
- %token K_COS
- %token K_EXP
- %token K_FABS
- %token K_FLOOR
- %token K_HYPOT
- %token K_LN
- %token K_LOG
- %token K_PI
- %token K_POW
- %token K_SIN
- %token K_SQRT
- %token K_TAN
- %token K_DTR
- %token K_RTD
- %token K_MAX
- %token K_MIN
- %token K_RND
-
- %token K_PV
- %token K_FV
- %token K_PMT
-
- %token K_HOUR
- %token K_MINUTE
- %token K_SECOND
- %token K_MONTH
- %token K_DAY
- %token K_YEAR
- %token K_NOW
- %token K_DATE
- %token K_FMT
- %token K_SUBSTR
- %token K_STON
- %token K_EQS
- %token K_EXT
- %token K_NVAL
- %token K_SVAL
- %token K_LOOKUP
- %token K_INDEX
- %token K_STINDEX
- %token K_AUTO
- %token K_AUTOCALC
- %token K_BYROWS
- %token K_BYCOLS
- %token K_BYGRAPH
- %token K_ITERATIONS
- %token K_NUMERIC
- %token K_PRESCALE
- %token K_EXTFUN
- %token K_CELLCUR
- %token K_TOPROW
- %token K_TBLSTYLE
- %token K_TBL
- %token K_LATEX
- %token K_TEX
-
- %left '?' ':'
- %left '|'
- %left '&'
- %nonassoc '<' '=' '>' '!'
- %left '+' '-' '#'
- %left '*' '/' '%'
- %left '^'
-
- %%
- command: S_LET var_or_range '=' e
- { let($2.left.vp, $4); }
- | S_LABEL var_or_range '=' e
- { slet($2.left.vp, $4, 0); }
- | S_LEFTSTRING var_or_range '=' e
- { slet($2.left.vp, $4, -1); }
- | S_RIGHTSTRING var_or_range '=' e
- { slet($2.left.vp, $4, 1); }
- | S_FORMAT COL ':' COL NUMBER NUMBER
- { doformat($2,$4,$5,$6); }
- | S_FORMAT COL NUMBER NUMBER
- { doformat($2,$2,$3,$4); }
- | S_GET strarg { /* This tmp hack is because readfile
- * recurses back through yyparse. */
- char *tmp;
- tmp = $2;
- readfile (tmp, 1);
- xfree(tmp);
- }
- | S_MERGE strarg {
- char *tmp;
- tmp = $2;
- readfile (tmp, 0);
- xfree(tmp);
- }
- | S_MDIR strarg
- { if (mdir) xfree(mdir); mdir = $2; }
- | S_PUT strarg range
- { (void) writefile($2, ($3.left.vp)->row,
- ($3.left.vp)->col, ($3.right.vp)->row,
- ($3.right.vp)->col);
- xfree($2); }
- | S_PUT strarg
- { (void) writefile ($2, 0, 0, maxrow, maxcol);
- xfree($2); }
- | S_WRITE strarg range { (void) printfile($2, ($3.left.vp)->row,
- ($3.left.vp)->col, ($3.right.vp)->row,
- ($3.right.vp)->col);
- xfree($2); }
- | S_WRITE strarg { (void) printfile ($2, 0, 0, maxrow, maxcol);
- xfree($2); }
- | S_TBL strarg range { (void) tblprintfile($2, ($3.left.vp)->row,
- ($3.left.vp)->col, ($3.right.vp)->row,
- ($3.right.vp)->col);
- xfree($2); }
- | S_TBL strarg { (void)tblprintfile ($2, 0, 0, maxrow, maxcol);
- xfree($2); }
- | S_SHOW COL ':' COL
- { showcol( $2, $4); }
- | S_SHOW NUMBER ':' NUMBER
- { showrow( $2, $4); }
- | S_HIDE COL
- { hide_col( $2 ); }
- | S_HIDE NUMBER
- { hide_row( $2 ); }
- | S_COPY range var_or_range
- { copy($2.left.vp,$2.right.vp,
- $3.left.vp,$3.right.vp); }
- | S_ERASE
- { eraser(lookat(showsr, showsc),
- lookat(currow, curcol)); }
- | S_ERASE var_or_range
- { eraser($2.left.vp, $2.right.vp); }
- | S_VALUE { valueize_area(showsr, showsc, currow, curcol);
- modflg++; }
- | S_VALUE var_or_range { valueize_area(($2.left.vp)->row,
- ($2.left.vp)->col,
- ($2.right.vp)->row,
- ($2.right.vp)->col); modflg++; }
- | S_FILL num num { fill(lookat(showsr, showsc),
- lookat(currow, curcol), $2, $3); }
- | S_FILL var_or_range num num
- { fill($2.left.vp, $2.right.vp, $3, $4); }
- | S_GOTO var_or_range {moveto($2.left.vp->row, $2.left.vp->col);}
- | S_GOTO num {num_search($2);}
- | S_GOTO STRING {str_search($2);}
- | S_GOTO {go_last();}
- | S_DEFINE strarg { struct ent_ptr arg1, arg2;
- arg1.vp = lookat(showsr, showsc);
- arg1.vf = 0;
- arg2.vp = lookat(currow, curcol);
- arg2.vf = 0;
- add_range($2, arg1, arg2, 1); }
-
- | S_DEFINE strarg range { add_range($2, $3.left, $3.right, 1); }
- | S_DEFINE strarg var { add_range($2, $3, $3, 0); }
- | S_UNDEFINE var_or_range { del_range($2.left.vp, $2.right.vp); }
- | S_SET setlist
- | /* nothing */
- | error;
-
- term: var { $$ = new_var('v', $1); }
- | K_FIXED term { $$ = new ('f', ENULL, $2); }
- | '@' K_SUM '(' var_or_range ')'
- { $$ = new_range(REDUCE | '+', $4); }
- | '@' K_PROD '(' var_or_range ')'
- { $$ = new_range (REDUCE | '*', $4); }
- | '@' K_AVG '(' var_or_range ')'
- { $$ = new_range (REDUCE | 'a', $4); }
- | '@' K_STDDEV '(' var_or_range ')'
- { $$ = new_range (REDUCE | 's', $4); }
- | '@' K_MAX '(' var_or_range ')'
- { $$ = new_range (REDUCE | MAX, $4); }
- | '@' K_MAX '(' e ',' expr_list ')'
- { $$ = new(LMAX, $6, $4); }
- | '@' K_MIN '(' var_or_range ')'
- { $$ = new_range (REDUCE | MIN, $4); }
- | '@' K_MIN '(' e ',' expr_list ')'
- { $$ = new(LMIN, $6, $4); }
- | '@' K_ACOS '(' e ')'
- { $$ = new(ACOS, ENULL, $4); }
- | '@' K_ASIN '(' e ')' { $$ = new(ASIN, ENULL, $4); }
- | '@' K_ATAN '(' e ')' { $$ = new(ATAN, ENULL, $4); }
- | '@' K_ATAN2 '(' e ',' e ')' { $$ = new(ATAN2, $4, $6); }
- | '@' K_CEIL '(' e ')' { $$ = new(CEIL, ENULL, $4); }
- | '@' K_COS '(' e ')' { $$ = new(COS, ENULL, $4); }
- | '@' K_EXP '(' e ')' { $$ = new(EXP, ENULL, $4); }
- | '@' K_FABS '(' e ')' { $$ = new(FABS, ENULL, $4); }
- | '@' K_FLOOR '(' e ')' { $$ = new(FLOOR, ENULL, $4); }
- | '@' K_HYPOT '(' e ',' e ')' { $$ = new(HYPOT, $4, $6); }
- | '@' K_LN '(' e ')' { $$ = new(LOG, ENULL, $4); }
- | '@' K_LOG '(' e ')' { $$ = new(LOG10, ENULL, $4); }
- | '@' K_POW '(' e ',' e ')' { $$ = new(POW, $4, $6); }
- | '@' K_SIN '(' e ')' { $$ = new(SIN, ENULL, $4); }
- | '@' K_SQRT '(' e ')' { $$ = new(SQRT, ENULL, $4); }
- | '@' K_TAN '(' e ')' { $$ = new(TAN, ENULL, $4); }
- | '@' K_DTR '(' e ')' { $$ = new(DTR, ENULL, $4); }
- | '@' K_RTD '(' e ')' { $$ = new(RTD, ENULL, $4); }
- | '@' K_RND '(' e ')' { $$ = new(RND, ENULL, $4); }
-
- | '@' K_PV '(' e ',' e ',' e ')' { $$ = new(PV, $4,new(':',$6,$8)); }
- | '@' K_FV '(' e ',' e ',' e ')' { $$ = new(FV, $4,new(':',$6,$8)); }
- | '@' K_PMT '(' e ',' e ',' e ')' { $$ = new(PMT, $4,new(':',$6,$8)); }
-
- | '@' K_HOUR '(' e ')' { $$ = new(HOUR,ENULL, $4); }
- | '@' K_MINUTE '(' e ')' { $$ = new(MINUTE,ENULL, $4); }
- | '@' K_SECOND '(' e ')' { $$ = new(SECOND,ENULL, $4); }
- | '@' K_MONTH '(' e ')' { $$ = new(MONTH,ENULL,$4); }
- | '@' K_DAY '(' e ')' { $$ = new(DAY, ENULL, $4); }
- | '@' K_YEAR '(' e ')' { $$ = new(YEAR, ENULL, $4); }
- | '@' K_NOW { $$ = new(NOW, ENULL, ENULL);}
- | '@' K_STON '(' e ')' { $$ = new(STON, ENULL, $4); }
- | '@' K_EQS '(' e ',' e ')' { $$ = new (EQS, $4, $6); }
- | '@' K_DATE '(' e ')' { $$ = new(DATE, ENULL, $4); }
- | '@' K_FMT '(' e ',' e ')' { $$ = new(FMT, $4, $6); }
- | '@' K_INDEX '(' e ',' var_or_range ')'
- { $$ = new(INDEX, $4, new_range(REDUCE | INDEX, $6)); }
- | '@' K_LOOKUP '(' e ',' var_or_range ')'
- { $$ = new(LOOKUP, $4, new_range(REDUCE | LOOKUP, $6)); }
- | '@' K_STINDEX '(' e ',' var_or_range ')'
- { $$ = new(STINDEX, $4, new_range(REDUCE | STINDEX, $6)); }
- | '@' K_EXT '(' e ',' e ')' { $$ = new(EXT, $4, $6); }
- | '@' K_NVAL '(' e ',' e ')' { $$ = new(NVAL, $4, $6); }
- | '@' K_SVAL '(' e ',' e ')' { $$ = new(SVAL, $4, $6); }
- | '@' K_SUBSTR '(' e ',' e ',' e ')'
- { $$ = new(SUBSTR, $4, new(',', $6, $8)); }
- | '(' e ')' { $$ = $2; }
- | '+' term { $$ = $2; }
- | '-' term { $$ = new ('m', ENULL, $2); }
- | NUMBER { $$ = new_const('k', (double) $1); }
- | FNUMBER { $$ = new_const('k', $1); }
- | K_PI { $$ = new_const('k', (double)3.14159265358979323846); }
- | STRING { $$ = new_str($1); }
- | '~' term { $$ = new ('~', ENULL, $2); }
- | '!' term { $$ = new ('~', ENULL, $2); }
- ;
-
- e: e '+' e { $$ = new ('+', $1, $3); }
- | e '-' e { $$ = new ('-', $1, $3); }
- | e '*' e { $$ = new ('*', $1, $3); }
- | e '/' e { $$ = new ('/', $1, $3); }
- | e '%' e { $$ = new ('%', $1, $3); }
- | e '^' e { $$ = new ('^', $1, $3); }
- | term
- | e '?' e ':' e { $$ = new ('?', $1, new(':', $3, $5)); }
- | e '<' e { $$ = new ('<', $1, $3); }
- | e '=' e { $$ = new ('=', $1, $3); }
- | e '>' e { $$ = new ('>', $1, $3); }
- | e '&' e { $$ = new ('&', $1, $3); }
- | e '|' e { $$ = new ('|', $1, $3); }
- | e '<' '=' e { $$ = new ('~', ENULL, new ('>', $1, $4)); }
- | e '!' '=' e { $$ = new ('~', ENULL, new ('=', $1, $4)); }
- | e '>' '=' e { $$ = new ('~', ENULL, new ('<', $1, $4)); }
- | e '#' e { $$ = new ('#', $1, $3); }
- ;
-
- expr_list: e { $$ = new(ELIST, ENULL, $1); }
- | expr_list ',' e { $$ = new(ELIST, $1, $3); }
- ;
-
- range: var ':' var { $$.left = $1; $$.right = $3; }
- | RANGE { $$ = $1; }
- ;
-
- var: COL NUMBER { $$.vp = lookat($2 , $1); $$.vf = 0;}
- | '$' COL NUMBER { $$.vp = lookat($3 , $2);
- $$.vf = FIX_COL;}
- | COL '$' NUMBER { $$.vp = lookat($3 , $1);
- $$.vf = FIX_ROW;}
- | '$' COL '$' NUMBER { $$.vp = lookat($4 , $2);
- $$.vf = FIX_ROW | FIX_COL;}
- | VAR { $$ = $1.left; }
- ;
-
- var_or_range: range { $$ = $1; }
- | var { $$.left = $1; $$.right = $1; }
- ;
-
- num: NUMBER { $$ = (double) $1; }
- | FNUMBER { $$ = $1; }
- | '-' num { $$ = -$2; }
- | '+' num { $$ = $2; }
- ;
-
- strarg: STRING { $$ = $1; }
- | var {
- char *s, *s1;
- s1 = $1.vp->label;
- if (!s1)
- s1 = "NULL_STRING";
- s = xmalloc((unsigned)strlen(s1)+1);
- (void) strcpy(s, s1);
- $$ = s;
- }
- ;
-
- setlist :
- | setlist setitem
- ;
-
- setitem : K_AUTO { setauto(1); }
- | K_AUTOCALC { setauto(1); }
- | '~' K_AUTO { setauto(0); }
- | '~' K_AUTOCALC { setauto(0); }
- | '!' K_AUTO { setauto(0); }
- | '!' K_AUTOCALC { setauto(0); }
- | K_BYCOLS { setorder(BYCOLS); }
- | K_BYROWS { setorder(BYROWS); }
- | K_BYGRAPH { setorder(BYGRAPH); }
- | K_NUMERIC { numeric = 1; }
- | '!' K_NUMERIC { numeric = 0; }
- | K_PRESCALE { prescale = 0.01; }
- | '!' K_PRESCALE { prescale = 1.0; }
- | K_EXTFUN { extfunc = 1; }
- | '!' K_EXTFUN { extfunc = 0; }
- | K_CELLCUR { showcell = 1; }
- | '!' K_CELLCUR { showcell = 0; }
- | K_TOPROW { showtop = 1; }
- | '!' K_TOPROW { showtop = 0; }
- | K_ITERATIONS '=' NUMBER { setiterations($3); }
- | K_TBLSTYLE '=' NUMBER { tbl_style = $3; }
- | K_TBLSTYLE '=' K_TBL { tbl_style = TBL; }
- | K_TBLSTYLE '=' K_LATEX { tbl_style = LATEX; }
- | K_TBLSTYLE '=' K_TEX { tbl_style = TEX; }
- ;
- \SHAR\EOF\
- else
- echo "will not over write ./gram.y"
- fi
- if [ `wc -c ./gram.y | awk '{printf $1}'` -ne 11263 ]
- then
- echo `wc -c ./gram.y | awk '{print "Got " $1 ", Expected " 11263}'`
- fi
- if `test ! -s ./interp.c`
- then
- echo "Extracting ./interp.c"
- cat > ./interp.c << '\SHAR\EOF\'
- /* SC A Spreadsheet Calculator
- * Expression interpreter and assorted support routines.
- *
- * original by James Gosling, September 1982
- * modified by Mark Weiser and Bruce Israel,
- * University of Maryland
- *
- * More mods Robert Bond, 12/86
- * More mods by Alan Silverstein, 3-4/88, see list of changes.
- * $Revision: 6.1 $
- */
-
- #include <math.h>
- #include <signal.h>
- #include <setjmp.h>
- #include <stdio.h>
-
- extern int errno; /* set by math functions */
- #ifdef BSD42
- #include <strings.h>
- #include <sys/time.h>
- #ifndef strchr
- #define strchr rindex
- #endif
- #else
- #include <time.h>
- #ifndef SYSIII
- #include <string.h>
- #endif
- #endif
-
- #include <curses.h>
- #include "sc.h"
-
- #if defined(BSD42) || defined(BSD43)
- char *re_comp();
- #endif
- #if defined(SYSV2) || defined(SYSV3)
- char *regcmp();
- char *regex();
- #endif
-
- #ifdef SIGVOID
- void quit();
- #else
- int quit();
- #endif
-
- /* Use this structure to save the the last 'g' command */
-
- struct go_save {
- int g_type;
- double g_n;
- char *g_s;
- int g_row;
- int g_col;
- } gs;
-
- /* g_type can be: */
-
- #define G_NONE 0 /* Starting value - must be 0*/
- #define G_NUM 1
- #define G_STR 2
- #define G_CELL 3
-
- extern FILE *popen();
-
- jmp_buf fpe_save;
- int exprerr; /* Set by eval() and seval() if expression errors */
- double prescale = 1.0; /* Prescale for constants in let() */
- int extfunc = 0; /* Enable/disable external functions */
- int loading = 0; /* Set when readfile() is active */
- double fn1_eval();
- double fn2_eval();
-
- #define PI (double)3.14159265358979323846
- #define dtr(x) ((x)*(PI/(double)180.0))
- #define rtd(x) ((x)*(180.0/(double)PI))
-
- double finfunc(fun,v1,v2,v3)
- int fun;
- double v1,v2,v3;
- {
- double answer,p;
-
- p = fn2_eval(pow, 1 + v2, v3);
-
- switch(fun)
- {
- case PV:
- answer = v1 * (1 - 1/p) / v2;
- break;
- case FV:
- answer = v1 * (p - 1) / v2;
- break;
- case PMT:
- answer = v1 * v2 / (1 - 1/p);
- break;
- }
- return(answer);
- }
-
- char *
- dostindex( val, minr, minc, maxr, maxc)
- double val;
- int minr, minc, maxr, maxc;
- {
- register r,c;
- register struct ent *p;
- char *pr;
- int x;
-
- x = (int) val;
- r = minr; c = minc;
- p = 0;
- if ( minr == maxr ) { /* look along the row */
- c = minc + x - 1;
- if (c <= maxc && c >=minc)
- p = tbl[r][c];
- } else if ( minc == maxc ) { /* look down the column */
- r = minr + x - 1;
- if (r <= maxr && r >=minr)
- p = tbl[r][c];
- } else {
- error ("range specified to @stindex");
- return(0);
- }
- if (p && p->label) {
- pr = xmalloc((unsigned)(strlen(p->label)+1));
- (void)strcpy(pr, p->label);
- return (pr);
- } else
- return(0);
- }
-
- double
- doindex( val, minr, minc, maxr, maxc)
- double val;
- int minr, minc, maxr, maxc;
- {
- double v;
- register r,c;
- register struct ent *p;
- int x;
-
- x = (int) val;
- v = 0;
- r = minr; c = minc;
- if ( minr == maxr ) { /* look along the row */
- c = minc + x - 1;
- if (c <= maxc && c >=minc
- && (p = tbl[r][c] ) && p->flags&is_valid )
- return p->v;
- }
- else if ( minc == maxc ){ /* look down the column */
- r = minr + x - 1;
- if (r <= maxr && r >=minr
- && (p = tbl[r][c] ) && p->flags&is_valid )
- return p->v;
- }
- else error(" range specified to @index");
- return v;
- }
-
- double
- dolookupn( val, minr, minc, maxr, maxc)
- double val;
- int minr, minc, maxr, maxc;
- {
- double v;
- register r,c;
- register struct ent *p;
-
- v = 0;
- r = minr; c = minc;
- if ( minr == maxr ) { /* look along the row */
- for ( c = minc; c <= maxc; c++) {
- if ( (p = tbl[r][c] ) && p->flags&is_valid ) {
- if(p->v <= val) {
- p = tbl[r+1][c];
- if ( p && p->flags&is_valid)
- v = p->v;
- }
- else return v;
- }
- }
- }
- else if ( minc == maxc ){ /* look down the column */
- for ( r = minr; r <= maxr; r++) {
- if ( (p = tbl[r][c] ) && p->flags&is_valid ) {
- if(p->v <= val) {
- p = tbl[r][c+1];
- if ( p && p->flags&is_valid)
- v = p->v;
- }
- else return v;
- }
- }
- }
- else error(" range specified to @lookup");
- return v;
- }
-
- double
- dolookups(s, minr, minc, maxr, maxc)
- char *s;
- int minr, minc, maxr, maxc;
- {
- double v;
- register r,c;
- register struct ent *p;
-
- v = 0;
- r = minr; c = minc;
- if ( minr == maxr ) { /* look along the row */
- for ( c = minc; c <= maxc; c++) {
- if ( (p = tbl[r][c] ) && p->label) {
- if(strcmp(s,p->label) == 0) {
- p = tbl[r+1][c];
- xfree(s);
- if ( p && p->flags & is_valid)
- return(p->v);
- }
- }
- }
- } else if ( minc == maxc ) { /* look down the column */
- for ( r = minr; r <= maxr; r++) {
- if ( (p = tbl[r][c] ) && p->label) {
- if(strcmp(s,p->label) == 0) {
- p = tbl[r][c+1];
- xfree(s);
- if ( p && p->flags & is_valid)
- return(p->v);
- }
- }
- }
- } else error(" range specified to @lookup");
- xfree(s);
- return v;
- }
-
- double
- dosum(minr, minc, maxr, maxc)
- int minr, minc, maxr, maxc;
- {
- double v;
- register r,c;
- register struct ent *p;
-
- v = 0;
- for (r = minr; r<=maxr; r++)
- for (c = minc; c<=maxc; c++)
- if ((p = tbl[r][c]) && p->flags&is_valid)
- v += p->v;
- return v;
- }
-
- double
- doprod(minr, minc, maxr, maxc)
- int minr, minc, maxr, maxc;
- {
- double v;
- register r,c;
- register struct ent *p;
-
- v = 1;
- for (r = minr; r<=maxr; r++)
- for (c = minc; c<=maxc; c++)
- if ((p = tbl[r][c]) && p->flags&is_valid)
- v *= p->v;
- return v;
- }
-
- double
- doavg(minr, minc, maxr, maxc)
- int minr, minc, maxr, maxc;
- {
- double v;
- register r,c,count;
- register struct ent *p;
-
- v = 0;
- count = 0;
- for (r = minr; r<=maxr; r++)
- for (c = minc; c<=maxc; c++)
- if ((p = tbl[r][c]) && p->flags&is_valid) {
- v += p->v;
- count++;
- }
-
- if (count == 0)
- return ((double) 0);
-
- return (v / (double)count);
- }
-
- double
- dostddev(minr, minc, maxr, maxc)
- int minr, minc, maxr, maxc;
- {
- double lp, rp, v, nd;
- register r,c,n;
- register struct ent *p;
-
- n = 0;
- lp = 0;
- rp = 0;
- for (r = minr; r<=maxr; r++)
- for (c = minc; c<=maxc; c++)
- if ((p = tbl[r][c]) && p->flags&is_valid) {
- v = p->v;
- lp += v*v;
- rp += v;
- n++;
- }
-
- if ((n == 0) || (n == 1))
- return ((double) 0);
- nd = (double)n;
- return (sqrt((nd*lp-rp*rp)/(nd*(nd-1))));
- }
-
- double
- domax(minr, minc, maxr, maxc)
- int minr, minc, maxr, maxc;
- {
- double v;
- register r,c,count;
- register struct ent *p;
-
- count = 0;
- for (r = minr; r<=maxr; r++)
- for (c = minc; c<=maxc; c++)
- if ((p = tbl[r][c]) && p->flags&is_valid) {
- if (!count) {
- v = p->v;
- count++;
- } else if (p->v > v)
- v = p->v;
- }
-
- if (count == 0)
- return ((double) 0);
-
- return (v);
- }
-
- double
- domin(minr, minc, maxr, maxc)
- int minr, minc, maxr, maxc;
- {
- double v;
- register r,c,count;
- register struct ent *p;
-
- count = 0;
- for (r = minr; r<=maxr; r++)
- for (c = minc; c<=maxc; c++)
- if ((p = tbl[r][c]) && p->flags&is_valid) {
- if (!count) {
- v = p->v;
- count++;
- } else if (p->v < v)
- v = p->v;
- }
-
- if (count == 0)
- return ((double) 0);
-
- return (v);
- }
-
- double
- dotime(which, when)
- int which;
- double when;
- {
- long time();
-
- static long t_cache;
- static struct tm *tp;
- long tloc;
-
- if (which == NOW)
- return (double)time((long *)0);
-
- tloc = (long)when;
-
- if (tloc != t_cache) {
- tp = localtime(&tloc);
- tp->tm_mon += 1;
- tp->tm_year += 1900;
- t_cache = tloc;
- }
-
- switch (which) {
- case HOUR: return((double)(tp->tm_hour));
- case MINUTE: return((double)(tp->tm_min));
- case SECOND: return((double)(tp->tm_sec));
- case MONTH: return((double)(tp->tm_mon));
- case DAY: return((double)(tp->tm_mday));
- case YEAR: return((double)(tp->tm_year));
- }
- /* Safety net */
- return (0.0);
- }
-
- double
- doston(s)
- char *s;
- {
- char *strtof();
- double v;
-
- if (!s)
- return((double)0.0);
-
- (void)strtof(s, &v);
- xfree(s);
- return(v);
- }
-
- double
- doeqs(s1, s2)
- char *s1, *s2;
- {
- double v;
-
- if (!s1 && !s2)
- return(1.0);
-
- if (!s1 || !s2)
- v = 0.0;
- else if (strcmp(s1, s2) == 0)
- v = 1.0;
- else
- v = 0.0;
-
- if (s1)
- xfree(s1);
-
- if (s2)
- xfree(s2);
-
- return(v);
- }
-
-
- /*
- * Given a string representing a column name and a value which is a column
- * number, return a pointer to the selected cell's entry, if any, else 0. Use
- * only the integer part of the column number. Always free the string.
- */
-
- struct ent *
- getent (colstr, rowdoub)
- char *colstr;
- double rowdoub;
- {
- int collen; /* length of string */
- int row, col; /* integer values */
- struct ent *ep = 0; /* selected entry */
-
- if (((row = (int) floor (rowdoub)) >= 0)
- && (row < MAXROWS) /* in range */
- && ((collen = strlen (colstr)) <= 2) /* not too long */
- && ((col = atocol (colstr, collen)) >= 0)
- && (col < MAXCOLS)) /* in range */
- {
- ep = tbl [row] [col];
- }
-
- xfree (colstr);
- return (ep);
- }
-
-
- /*
- * Given a string representing a column name and a value which is a column
- * number, return the selected cell's numeric value, if any.
- */
-
- double
- donval (colstr, rowdoub)
- char *colstr;
- double rowdoub;
- {
- struct ent *ep;
-
- return (((ep = getent (colstr, rowdoub)) && ((ep -> flags) & is_valid)) ?
- (ep -> v) : 0);
- }
-
-
- /*
- * The list routines (e.g. dolmax) are called with an LMAX enode.
- * The left pointer is a chain of ELIST nodes, the right pointer
- * is a value.
- */
- double
- dolmax(ep)
- struct enode *ep;
- {
- register int count = 0;
- register double maxval = 0; /* Assignment to shut up lint */
- register struct enode *p;
- register double v;
-
- for (p = ep; p; p = p->e.o.left) {
- v = eval(p->e.o.right);
- if (!count || v > maxval) {
- maxval = v; count++;
- }
- }
- if (count) return maxval;
- else return 0.0;
- }
-
- double
- dolmin(ep)
- struct enode *ep;
- {
- register int count = 0;
- register double minval = 0; /* Assignment to shut up lint */
- register struct enode *p;
- register double v;
-
- for (p = ep; p; p = p->e.o.left) {
- v = eval(p->e.o.right);
- if (!count || v < minval) {
- minval = v; count++;
- }
- }
- if (count) return minval;
- else return 0.0;
- }
-
- double
- eval(e)
- register struct enode *e;
- {
-
- if (e==0) return 0;
- switch (e->op) {
- case '+': return (eval(e->e.o.left) + eval(e->e.o.right));
- case '-': return (eval(e->e.o.left) - eval(e->e.o.right));
- case '*': return (eval(e->e.o.left) * eval(e->e.o.right));
- case '/': return (eval(e->e.o.left) / eval(e->e.o.right));
- case '%': { double num, denom;
- num = floor(eval(e->e.o.left));
- denom = floor(eval (e->e.o.right));
- return denom ? num - floor(num/denom)*denom : 0; }
- case '^': return (fn2_eval(pow,eval(e->e.o.left),eval(e->e.o.right)));
- case '<': return (eval(e->e.o.left) < eval(e->e.o.right));
- case '=': return (eval(e->e.o.left) == eval(e->e.o.right));
- case '>': return (eval(e->e.o.left) > eval(e->e.o.right));
- case '&': return (eval(e->e.o.left) && eval(e->e.o.right));
- case '|': return (eval(e->e.o.left) || eval(e->e.o.right));
- case '?': return eval(e->e.o.left) ? eval(e->e.o.right->e.o.left)
- : eval(e->e.o.right->e.o.right);
- case 'm': return (-eval(e->e.o.right));
- case 'f': return (eval(e->e.o.right));
- case '~': return (eval(e->e.o.right) == 0.0);
- case 'k': return (e->e.k);
- case 'v': return (e->e.v.vp->v);
- case INDEX:
- case LOOKUP:
- { register r,c;
- register maxr, maxc;
- register minr, minc;
- maxr = e->e.o.right->e.r.right.vp -> row;
- maxc = e->e.o.right->e.r.right.vp -> col;
- minr = e->e.o.right->e.r.left.vp -> row;
- minc = e->e.o.right->e.r.left.vp -> col;
- if (minr>maxr) r = maxr, maxr = minr, minr = r;
- if (minc>maxc) c = maxc, maxc = minc, minc = c;
- switch(e->op){
- case LOOKUP:
- if (etype(e->e.o.left) == NUM)
- return dolookupn(eval(e->e.o.left), minr, minc, maxr, maxc);
- else
- return dolookups(seval(e->e.o.left),minr, minc, maxr, maxc);
- case INDEX:
- return doindex(eval(e->e.o.left), minr, minc, maxr, maxc);
- }
- }
- case REDUCE | '+':
- case REDUCE | '*':
- case REDUCE | 'a':
- case REDUCE | 's':
- case REDUCE | MAX:
- case REDUCE | MIN:
- { register r,c;
- register maxr, maxc;
- register minr, minc;
- maxr = e->e.r.right.vp -> row;
- maxc = e->e.r.right.vp -> col;
- minr = e->e.r.left.vp -> row;
- minc = e->e.r.left.vp -> col;
- if (minr>maxr) r = maxr, maxr = minr, minr = r;
- if (minc>maxc) c = maxc, maxc = minc, minc = c;
- switch (e->op) {
- case REDUCE | '+': return dosum(minr, minc, maxr, maxc);
- case REDUCE | '*': return doprod(minr, minc, maxr, maxc);
- case REDUCE | 'a': return doavg(minr, minc, maxr, maxc);
- case REDUCE | 's': return dostddev(minr, minc, maxr, maxc);
- case REDUCE | MAX: return domax(minr, minc, maxr, maxc);
- case REDUCE | MIN: return domin(minr, minc, maxr, maxc);
- }
- }
- case ACOS: return (fn1_eval( acos, eval(e->e.o.right)));
- case ASIN: return (fn1_eval( asin, eval(e->e.o.right)));
- case ATAN: return (fn1_eval( atan, eval(e->e.o.right)));
- case ATAN2: return (fn2_eval( atan2, eval(e->e.o.left), eval(e->e.o.right)));
- case CEIL: return (fn1_eval( ceil, eval(e->e.o.right)));
- case COS: return (fn1_eval( cos, eval(e->e.o.right)));
- case EXP: return (fn1_eval( exp, eval(e->e.o.right)));
- case FABS: return (fn1_eval( fabs, eval(e->e.o.right)));
- case FLOOR: return (fn1_eval( floor, eval(e->e.o.right)));
- case HYPOT: return (fn2_eval( hypot, eval(e->e.o.left), eval(e->e.o.right)));
- case LOG: return (fn1_eval( log, eval(e->e.o.right)));
- case LOG10: return (fn1_eval( log10, eval(e->e.o.right)));
- case POW: return (fn2_eval( pow, eval(e->e.o.left), eval(e->e.o.right)));
- case SIN: return (fn1_eval( sin, eval(e->e.o.right)));
- case SQRT: return (fn1_eval( sqrt, eval(e->e.o.right)));
- case TAN: return (fn1_eval( tan, eval(e->e.o.right)));
- case DTR: return (dtr(eval(e->e.o.right)));
- case RTD: return (rtd(eval(e->e.o.right)));
- case RND: {
- double temp;
- temp = eval(e->e.o.right);
- return(temp-floor(temp) < 0.5 ?
- floor(temp) : ceil(temp));
- }
- case FV:
- case PV:
- case PMT: return(finfunc(e->op,eval(e->e.o.left),
- eval(e->e.o.right->e.o.left),
- eval(e->e.o.right->e.o.right)));
- case HOUR: return (dotime(HOUR, eval(e->e.o.right)));
- case MINUTE: return (dotime(MINUTE, eval(e->e.o.right)));
- case SECOND: return (dotime(SECOND, eval(e->e.o.right)));
- case MONTH: return (dotime(MONTH, eval(e->e.o.right)));
- case DAY: return (dotime(DAY, eval(e->e.o.right)));
- case YEAR: return (dotime(YEAR, eval(e->e.o.right)));
- case NOW: return (dotime(NOW, (double)0.0));
- case STON: return (doston(seval(e->e.o.right)));
- case EQS: return (doeqs(seval(e->e.o.right),seval(e->e.o.left)));
- case LMAX: return dolmax(e);
- case LMIN: return dolmin(e);
- case NVAL: return (donval(seval(e->e.o.left),eval(e->e.o.right)));
- default: error ("Illegal numeric expression");
- exprerr = 1;
- return((double)0.0);
- }
- #ifdef sequent
- return((double)0.0); /* Quiet a questionable compiler complaint */
- #endif
- }
-
- #ifdef SIGVOID
- void
- #endif
- eval_fpe() /* Trap for FPE errors in eval */
- {
- longjmp(fpe_save, 1);
- }
-
- double fn1_eval(fn, arg)
- double (*fn)();
- double arg;
- {
- double res;
- errno = 0;
- res = (*fn)(arg);
- if(errno)
- eval_fpe();
-
- return res;
- }
-
- double fn2_eval(fn, arg1, arg2)
- double (*fn)();
- double arg1, arg2;
- {
- double res;
- errno = 0;
- res = (*fn)(arg1, arg2);
- if(errno)
- eval_fpe();
-
- return res;
- }
-
- /*
- * Rules for string functions:
- * Take string arguments which they xfree.
- * All returned strings are assumed to be xalloced.
- */
-
- char *
- docat(s1, s2)
- register char *s1, *s2;
- {
- register char *p;
- char *arg1, *arg2;
-
- if (!s1 && !s2)
- return(0);
- arg1 = s1 ? s1 : "";
- arg2 = s2 ? s2 : "";
- p = xmalloc((unsigned)(strlen(arg1)+strlen(arg2)+1));
- (void) strcpy(p, arg1);
- (void) strcat(p, arg2);
- if (s1)
- xfree(s1);
- if (s2)
- xfree(s2);
- return(p);
- }
-
- char *
- dodate(tloc)
- long tloc;
- {
- char *tp;
- char *p;
-
- tp = ctime(&tloc);
- tp[24] = 0;
- p = xmalloc((unsigned)25);
- (void) strcpy(p, tp);
- return(p);
- }
-
-
- char *
- dofmt(fmtstr, v)
- char *fmtstr;
- double v;
- {
- char buff[1024];
- char *p;
-
- if (!fmtstr)
- return(0);
- (void)sprintf(buff, fmtstr, v);
- p = xmalloc((unsigned)(strlen(buff)+1));
- (void) strcpy(p, buff);
- xfree(fmtstr);
- return(p);
- }
-
-
- /*
- * Given a command name and a value, run the command with the given value and
- * read and return its first output line (only) as an allocated string, always
- * a copy of prevstr, which is set appropriately first unless external
- * functions are disabled, in which case the previous value is used. The
- * handling of prevstr and freeing of command is tricky. Returning an
- * allocated string in all cases, even if null, insures cell expressions are
- * written to files, etc.
- */
-
- #ifdef VMS
- char *
- doext(command, value)
- char *command;
- double value;
- {
- error("Warning: External functions unavailable on VMS");
- if (command)
- xfree(command);
- return (strcpy (xmalloc((unsigned) 1), "\0"));
- }
-
- #else /* VMS */
-
- char *
- doext (command, value)
- char *command;
- double value;
- {
- static char *prevstr = 0; /* previous result */
- char buff[1024]; /* command line/return, not permanently alloc */
-
- if (!prevstr) {
- prevstr = xmalloc((unsigned)1);
- *prevstr = 0;
- }
- if (!extfunc) {
- error ("Warning: external functions disabled; using %s value",
- prevstr ? "previous" : "null");
-
- if (command) xfree (command);
- } else {
- if (prevstr) xfree (prevstr); /* no longer needed */
- prevstr = 0;
-
- if ((! command) || (! *command)) {
- error ("Warning: external function given null command name");
- if (command) xfree (command);
- } else {
- FILE *pp;
-
- (void) sprintf (buff, "%s %g", command, value); /* build cmd line */
- xfree (command);
-
- error ("Running external function...");
- (void) refresh();
-
- if ((pp = popen (buff, "r")) == (FILE *) NULL) /* run it */
- error ("Warning: running \"%s\" failed", buff);
- else {
- if (fgets (buff, 1024, pp) == NULL) /* one line */
- error ("Warning: external function returned nothing");
- else {
- char *cp;
-
- error (""); /* erase notice */
- buff[1023] = 0;
-
- if (cp = strchr (buff, '\n')) /* contains newline */
- *cp = 0; /* end string there */
-
- (void) strcpy (prevstr =
- xmalloc ((unsigned) (strlen (buff) + 1)), buff);
- /* save alloc'd copy */
- }
- (void) pclose (pp);
-
- } /* else */
- } /* else */
- } /* else */
- return (strcpy (xmalloc ((unsigned) (strlen (prevstr) + 1)), prevstr));
- }
-
- #endif /* VMS */
-
-
- /*
- * Given a string representing a column name and a value which is a column
- * number, return the selected cell's string value, if any. Even if none,
- * still allocate and return a null string so the cell has a label value so
- * the expression is saved in a file, etc.
- */
-
- char *
- dosval (colstr, rowdoub)
- char *colstr;
- double rowdoub;
- {
- struct ent *ep;
- char *label;
-
- label = (ep = getent (colstr, rowdoub)) ? (ep -> label) : "";
- return (strcpy (xmalloc ((unsigned) (strlen (label) + 1)), label));
- }
-
-
- /*
- * Substring: Note that v1 and v2 are one-based to users, but zero-based
- * when calling this routine.
- */
-
- char *
- dosubstr(s, v1, v2)
- char *s;
- register int v1,v2;
- {
- register char *s1, *s2;
- char *p;
-
- if (!s)
- return(0);
-
- if (v2 >= strlen (s)) /* past end */
- v2 = strlen (s) - 1; /* to end */
-
- if (v1 < 0 || v1 > v2) { /* out of range, return null string */
- xfree(s);
- p = xmalloc((unsigned)1);
- p[0] = 0;
- return(p);
- }
- s2 = p = xmalloc((unsigned)(v2-v1+2));
- s1 = &s[v1];
- for(; v1 <= v2; s1++, s2++, v1++)
- *s2 = *s1;
- *s2 = 0;
- xfree(s);
- return(p);
- }
-
- char *
- seval(se)
- register struct enode *se;
- {
- register char *p;
-
- if (se==0) return 0;
- switch (se->op) {
- case O_SCONST: p = xmalloc((unsigned)(strlen(se->e.s)+1));
- (void) strcpy(p, se->e.s);
- return(p);
- case O_VAR: {
- struct ent *ep;
- ep = se->e.v.vp;
-
- if (!ep->label)
- return(0);
- p = xmalloc((unsigned)(strlen(ep->label)+1));
- (void) strcpy(p, ep->label);
- return(p);
- }
- case '#': return(docat(seval(se->e.o.left), seval(se->e.o.right)));
- case 'f': return(seval(se->e.o.right));
- case '?': return(eval(se->e.o.left) ? seval(se->e.o.right->e.o.left)
- : seval(se->e.o.right->e.o.right));
- case DATE: return(dodate((long)(eval(se->e.o.right))));
- case FMT: return(dofmt(seval(se->e.o.left), eval(se->e.o.right)));
- case STINDEX:
- { register r,c;
- register maxr, maxc;
- register minr, minc;
- maxr = se->e.o.right->e.r.right.vp -> row;
- maxc = se->e.o.right->e.r.right.vp -> col;
- minr = se->e.o.right->e.r.left.vp -> row;
- minc = se->e.o.right->e.r.left.vp -> col;
- if (minr>maxr) r = maxr, maxr = minr, minr = r;
- if (minc>maxc) c = maxc, maxc = minc, minc = c;
- return dostindex(eval(se->e.o.left), minr, minc, maxr, maxc);
- }
- case EXT: return(doext(seval(se->e.o.left), eval(se->e.o.right)));
- case SVAL: return(dosval(seval(se->e.o.left), eval(se->e.o.right)));
- case SUBSTR: return(dosubstr(seval(se->e.o.left),
- (int)eval(se->e.o.right->e.o.left) - 1,
- (int)eval(se->e.o.right->e.o.right) - 1));
- default:
- error ("Illegal string expression");
- exprerr = 1;
- return(0);
- }
- }
-
- /*
- * The graph formed by cell expressions which use other cells's values is not
- * evaluated "bottom up". The whole table is merely re-evaluated cell by cell,
- * top to bottom, left to right, in RealEvalAll(). Each cell's expression uses
- * constants in other cells. However, RealEvalAll() notices when a cell gets a
- * new numeric or string value, and reports if this happens for any cell.
- * EvalAll() repeats calling RealEvalAll() until there are no changes or the
- * evaluation count expires.
- */
-
- int propagation = 10; /* max number of times to try calculation */
-
- setiterations(i)
- int i;
- {
- if(i<1){
- error("iteration count must be at least 1");
- propagation = 1;
- }
- else propagation = i;
- }
-
- EvalAll () {
- int lastcnt, repct = 0;
-
- while ((lastcnt = RealEvalAll()) && (repct++ <= propagation));
- if((propagation>1)&& (lastcnt >0 ))
- error("Still changing after %d iterations",propagation-1);
- }
-
- /*
- * Evaluate all cells which have expressions and alter their numeric or string
- * values. Return the number of cells which changed.
- */
-
- int
- RealEvalAll () {
- register int i,j;
- int chgct = 0;
- register struct ent *p;
-
- (void) signal(SIGFPE, eval_fpe);
- if(calc_order == BYROWS ) {
- for (i=0; i<=maxrow; i++)
- for (j=0; j<=maxcol; j++)
- if ((p=tbl[i][j]) && p->expr) RealEvalOne(p,i,j, &chgct);
- }
- else if ( calc_order == BYCOLS ) {
- for (j=0; j<=maxcol; j++)
- for (i=0; i<=maxrow; i++)
- if ((p=tbl[i][j]) && p->expr) RealEvalOne(p,i,j, &chgct);
- }
- else error("Internal error calc_order");
-
- (void) signal(SIGFPE, quit);
- return(chgct);
- }
-
- RealEvalOne(p, i , j, chgct)
- register struct ent *p;
- int i, j, *chgct;
- {
- if (p->flags & is_strexpr) {
- char *v;
- if (setjmp(fpe_save)) {
- error("Floating point exception %s", v_name( i, j));
- v = "";
- } else {
- v = seval(p->expr);
- }
- if (!v && !p->label) /* Everything's fine */
- return;
- if (!p->label || !v || strcmp(v, p->label) != 0) {
- (*chgct)++;
- p->flags |= is_changed;
- }
- if(p->label)
- xfree(p->label);
- p->label = v;
- } else {
- double v;
- if (setjmp(fpe_save)) {
- error("Floating point exception %s", v_name( i, j));
- v = 0.0;
- } else {
- v = eval (p->expr);
- }
- if (v != p->v) {
- p->v = v; (*chgct)++;
- p->flags |= is_changed|is_valid;
- }
- }
- }
-
- struct enode *
- new(op, a1, a2)
- struct enode *a1, *a2;
- {
- register struct enode *p;
- p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
- p->op = op;
- p->e.o.left = a1;
- p->e.o.right = a2;
- return p;
- }
-
- struct enode *
- new_var(op, a1)
- struct ent_ptr a1;
- {
- register struct enode *p;
- p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
- p->op = op;
- p->e.v = a1;
- return p;
- }
-
- struct enode *
- new_range(op, a1)
- struct range_s a1;
- {
- register struct enode *p;
- p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
- p->op = op;
- p->e.r = a1;
- return p;
- }
-
- struct enode *
- new_const(op, a1)
- double a1;
- {
- register struct enode *p;
- p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
- p->op = op;
- p->e.k = a1;
- return p;
- }
-
- struct enode *
- new_str(s)
- char *s;
- {
- register struct enode *p;
-
- p = (struct enode *) xmalloc ((unsigned)sizeof(struct enode));
- p->op = O_SCONST;
- p->e.s = s;
- return(p);
- }
-
- copy(dv1, dv2, v1, v2)
- struct ent *dv1, *dv2, *v1, *v2;
- {
- int minsr, minsc;
- int maxsr, maxsc;
- int mindr, mindc;
- int maxdr, maxdc;
- int vr, vc;
- int r, c;
-
- mindr = dv1->row;
- mindc = dv1->col;
- maxdr = dv2->row;
- maxdc = dv2->col;
- if (mindr>maxdr) r = maxdr, maxdr = mindr, mindr = r;
- if (mindc>maxdc) c = maxdc, maxdc = mindc, mindc = c;
- maxsr = v2->row;
- maxsc = v2->col;
- minsr = v1->row;
- minsc = v1->col;
- if (minsr>maxsr) r = maxsr, maxsr = minsr, minsr = r;
- if (minsc>maxsc) c = maxsc, maxsc = minsc, minsc = c;
- if (maxdr >= MAXROWS ||
- maxdc >= MAXCOLS) {
- error ("The table can't be any bigger");
- return;
- }
- erase_area(mindr, mindc, maxdr, maxdc);
- if (minsr == maxsr && minsc == maxsc) {
- /* Source is a single cell */
- for(vr = mindr; vr <= maxdr; vr++)
- for (vc = mindc; vc <= maxdc; vc++)
- copyrtv(vr, vc, minsr, minsc, maxsr, maxsc);
- } else if (minsr == maxsr) {
- /* Source is a single row */
- for (vr = mindr; vr <= maxdr; vr++)
- copyrtv(vr, mindc, minsr, minsc, maxsr, maxsc);
- } else if (minsc == maxsc) {
- /* Source is a single column */
- for (vc = mindc; vc <= maxdc; vc++)
- copyrtv(mindr, vc, minsr, minsc, maxsr, maxsc);
- } else {
- /* Everything else */
- copyrtv(mindr, mindc, minsr, minsc, maxsr, maxsc);
- }
- sync_refs();
- }
-
- copyrtv(vr, vc, minsr, minsc, maxsr, maxsc)
- int vr, vc, minsr, minsc, maxsr, maxsc;
- {
- register struct ent *p;
- register struct ent *n;
- register int sr, sc;
- register int dr, dc;
-
- for (dr=vr, sr=minsr; sr<=maxsr; sr++, dr++)
- for (dc=vc, sc=minsc; sc<=maxsc; sc++, dc++) {
- n = lookat (dr, dc);
- (void) clearent(n);
- if (p = tbl[sr][sc])
- copyent( n, p, dr - sr, dc - sc);
- }
- }
-
- eraser(v1, v2)
- struct ent *v1, *v2;
- {
- FullUpdate++;
- flush_saved();
- erase_area(v1->row, v1->col, v2->row, v2->col);
- sync_refs();
- }
-
- /* Goto subroutines */
-
- g_free()
- {
- switch (gs.g_type) {
- case G_STR: xfree(gs.g_s); break;
- default: break;
- }
- gs.g_type = G_NONE;
- }
-
- go_last()
- {
- switch (gs.g_type) {
- case G_NONE:
- error("Nothing to repeat"); break;
- case G_NUM:
- num_search(gs.g_n);
- break;
- case G_CELL:
- moveto(gs.g_row, gs.g_col);
- break;
- case G_STR:
- gs.g_type = G_NONE; /* Don't free the string */
- str_search(gs.g_s);
- break;
-
- default: error("go_last: internal error");
- }
- }
-
- moveto(row, col)
- int row, col;
- {
- currow = row;
- curcol = col;
- g_free();
- gs.g_type = G_CELL;
- gs.g_row = currow;
- gs.g_col = curcol;
- }
-
- num_search(n)
- double n;
- {
- register struct ent *p;
- register int r,c;
-
- g_free();
- gs.g_type = G_NUM;
- gs.g_n = n;
-
- r = currow;
- c = curcol;
- do {
- if (c < maxcol)
- c++;
- else {
- if (r < maxrow) {
- while(++r < maxrow && row_hidden[r]) /* */;
- c = 0;
- } else {
- r = 0;
- c = 0;
- }
- }
- if (r == currow && c == curcol) {
- error("Number not found");
- return;
- }
- p = tbl[r][c];
- } while(col_hidden[c] || !p || p && (!(p->flags & is_valid)
- || (p->flags&is_valid) && p->v != n));
- currow = r;
- curcol = c;
- }
-
-
- str_search(s)
- char *s;
- {
- register struct ent *p;
- register int r,c;
- char *tmp;
-
- #if defined(BSD42) || defined(BSD43)
- if ((tmp = re_comp(s)) != (char *)0) {
- xfree(s);
- error(tmp);
- return;
- }
- #endif
- #if defined(SYSV2) || defined(SYSV3)
- if ((tmp = regcmp(s, (char *)0)) == (char *)0) {
- xfree(s);
- error("Invalid search string");
- return;
- }
- #endif
- g_free();
- gs.g_type = G_STR;
- gs.g_s = s;
- r = currow;
- c = curcol;
- do {
- if (c < maxcol)
- c++;
- else {
- if (r < maxrow) {
- while(++r < maxrow && row_hidden[r]) /* */;
- c = 0;
- } else {
- r = 0;
- c = 0;
- }
- }
- if (r == currow && c == curcol) {
- error("String not found");
- #if defined(SYSV2) || defined(SYSV3)
- free(tmp);
- #endif
- return;
- }
- p = tbl[r][c];
- } while(col_hidden[c] || !p || p && (!(p->label)
- #if defined(BSD42) || defined(BSD43)
- || (re_exec(p->label) == 0)));
- #else
- #if defined(SYSV2) || defined(SYSV3)
- || (regex(tmp, p->label) == (char *)0)));
- #else
- || (strcmp(s, p->label) != 0)));
- #endif
- #endif
- currow = r;
- curcol = c;
- #if defined(SYSV2) || defined(SYSV3)
- free(tmp);
- #endif
- }
-
- fill (v1, v2, start, inc)
- struct ent *v1, *v2;
- double start, inc;
- {
- register r,c;
- register struct ent *n;
- int maxr, maxc;
- int minr, minc;
-
- maxr = v2->row;
- maxc = v2->col;
- minr = v1->row;
- minc = v1->col;
- if (minr>maxr) r = maxr, maxr = minr, minr = r;
- if (minc>maxc) c = maxc, maxc = minc, minc = c;
- if (maxr >= MAXROWS) maxr = MAXROWS-1;
- if (maxc >= MAXCOLS) maxc = MAXCOLS-1;
- if (minr < 0) minr = 0;
- if (minr < 0) minr = 0;
-
- FullUpdate++;
- if( calc_order == BYROWS ) {
- for (r = minr; r<=maxr; r++)
- for (c = minc; c<=maxc; c++) {
- n = lookat (r, c);
- (void) clearent(n);
- n->v = start;
- start += inc;
- n->flags |= (is_changed|is_valid);
- }
- }
- else if ( calc_order == BYCOLS ) {
- for (c = minc; c<=maxc; c++)
- for (r = minr; r<=maxr; r++) {
- n = lookat (r, c);
- (void) clearent(n);
- n->v = start;
- start += inc;
- n->flags |= (is_changed|is_valid);
- }
- }
- else error(" Internal error calc_order");
- }
-
- let (v, e)
- struct ent *v;
- struct enode *e;
- {
- double val;
-
- exprerr = 0;
- (void) signal(SIGFPE, eval_fpe);
- if (setjmp(fpe_save)) {
- error ("Floating point exception in cell %s", v_name(v->row, v->col));
- val = 0.0;
- } else {
- val = eval(e);
- }
- (void) signal(SIGFPE, quit);
- if (exprerr) {
- efree(e);
- return;
- }
- if (constant(e)) {
- if (!loading)
- v->v = val * prescale;
- else
- v->v = val;
- if (!(v->flags & is_strexpr)) {
- efree (v->expr);
- v->expr = 0;
- }
- efree(e);
- v->flags |= (is_changed|is_valid);
- changed++;
- modflg++;
- return;
- }
- efree (v->expr);
- v->expr = e;
- v->flags |= (is_changed|is_valid);
- v->flags &= ~is_strexpr;
- changed++;
- modflg++;
- }
-
- slet (v, se, flushdir)
- struct ent *v;
- struct enode *se;
- int flushdir;
- {
- char *p;
-
- exprerr = 0;
- (void) signal(SIGFPE, eval_fpe);
- if (setjmp(fpe_save)) {
- error ("Floating point exception in cell %s", v_name(v->row, v->col));
- p = "";
- } else {
- p = seval(se);
- }
- (void) signal(SIGFPE, quit);
- if (exprerr) {
- efree(se);
- return;
- }
- if (constant(se)) {
- label(v, p, flushdir);
- if (p)
- xfree(p);
- efree(se);
- if (v->flags & is_strexpr) {
- efree (v->expr);
- v->expr = 0;
- v->flags &= ~is_strexpr;
- }
- return;
- }
- efree (v->expr);
- v->expr = se;
- v->flags |= (is_changed|is_strexpr);
- if (flushdir<0) v->flags |= is_leftflush;
- else v->flags &= ~is_leftflush;
- FullUpdate++;
- changed++;
- modflg++;
- }
-
- hide_row(arg)
- int arg;
- {
- if (arg < 0) {
- error("Invalid Range");
- return;
- }
- if (arg > MAXROWS-2) {
- error("You can't hide the last row");
- return;
- }
- FullUpdate++;
- row_hidden[arg] = 1;
- }
-
- hide_col(arg)
- int arg;
- {
- if (arg < 0) {
- error("Invalid Range");
- return;
- }
- if (arg > MAXCOLS-2) {
- error("You can't hide the last col");
- return;
- }
- FullUpdate++;
- col_hidden[arg] = 1;
- }
-
- clearent (v)
- struct ent *v;
- {
- if (!v)
- return;
- label(v,"",-1);
- v->v = 0;
- if (v->expr)
- efree(v->expr);
- v->expr = 0;
- v->flags |= (is_changed);
- v->flags &= ~(is_valid);
- changed++;
- modflg++;
- }
-
- /*
- * Say if an expression is a constant (return 1) or not.
- */
-
- constant (e)
- register struct enode *e;
- {
- return ((e == 0)
- || ((e -> op) == O_CONST)
- || ((e -> op) == O_SCONST)
- || (((e -> op) != O_VAR)
- && (((e -> op) & REDUCE) != REDUCE)
- && constant (e -> e.o.left)
- && constant (e -> e.o.right)
- && (e -> op != EXT) /* functions look like constants but aren't */
- && (e -> op != NVAL)
- && (e -> op != SVAL)
- && (e -> op != NOW)));
- }
-
- efree (e)
- register struct enode *e;
- {
- if (e) {
- if (e->op != O_VAR && e->op !=O_CONST && e->op != O_SCONST
- && (e->op & REDUCE) != REDUCE) {
- efree(e->e.o.left);
- efree(e->e.o.right);
- }
- if (e->op == O_SCONST && e->e.s)
- xfree(e->e.s);
- xfree ((char *)e);
- }
- }
-
- label (v, s, flushdir)
- register struct ent *v;
- register char *s;
- {
- if (v) {
- if (flushdir==0 && v->flags&is_valid) {
- register struct ent *tv;
- if (v->col>0 && ((tv=lookat(v->row,v->col-1))->flags&is_valid)==0)
- v = tv, flushdir = 1;
- else if (((tv=lookat (v->row,v->col+1))->flags&is_valid)==0)
- v = tv, flushdir = -1;
- else flushdir = -1;
- }
- if (v->label) xfree((char *)(v->label));
- if (s && s[0]) {
- v->label = xmalloc ((unsigned)(strlen(s)+1));
- (void) strcpy (v->label, s);
- } else
- v->label = 0;
- if (flushdir<0) v->flags |= is_leftflush;
- else v->flags &= ~is_leftflush;
- FullUpdate++;
- modflg++;
- }
- }
-
- decodev (v)
- struct ent_ptr v;
- {
- register struct range *r;
-
- if (!v.vp) (void)sprintf (line+linelim,"VAR?");
- else if (r = find_range((char *)0, 0, v.vp, v.vp))
- (void)sprintf(line+linelim, "%s", r->r_name);
- else
- (void)sprintf (line+linelim, "%s%s%s%d",
- v.vf & FIX_COL ? "$" : "",
- coltoa(v.vp->col),
- v.vf & FIX_ROW ? "$" : "",
- v.vp->row);
- linelim += strlen (line+linelim);
- }
-
- char *
- coltoa(col)
- int col;
- {
- static char rname[3];
- register char *p = rname;
-
- if (col > 25) {
- *p++ = col/26 + 'A' - 1;
- col %= 26;
- }
- *p++ = col+'A';
- *p = 0;
- return(rname);
- }
-
- /*
- * To make list elements come out in the same order
- * they were entered, we must do a depth-first eval
- * of the ELIST tree
- */
- static
- decompile_list(p)
- struct enode *p;
- {
- if (!p) return;
- decompile_list(p->e.o.left); /* depth first */
- decompile(p->e.o.right, 0);
- line[linelim++] = ',';
- }
-
- decompile(e, priority)
- register struct enode *e; {
- register char *s;
- if (e) {
- int mypriority;
- switch (e->op) {
- default: mypriority = 99; break;
- case '?': mypriority = 1; break;
- case ':': mypriority = 2; break;
- case '|': mypriority = 3; break;
- case '&': mypriority = 4; break;
- case '<': case '=': case '>': mypriority = 6; break;
- case '+': case '-': case '#': mypriority = 8; break;
- case '*': case '/': case '%': mypriority = 10; break;
- case '^': mypriority = 12; break;
- }
- if (mypriority<priority) line[linelim++] = '(';
- switch (e->op) {
- case 'f': for (s="fixed "; line[linelim++] = *s++;);
- linelim--;
- decompile (e->e.o.right, 30);
- break;
- case 'm': line[linelim++] = '-';
- decompile (e->e.o.right, 30);
- break;
- case '~': line[linelim++] = '~';
- decompile (e->e.o.right, 30);
- break;
- case 'v': decodev (e->e.v);
- break;
- case 'k': (void)sprintf (line+linelim,"%.15g",e->e.k);
- linelim += strlen (line+linelim);
- break;
- case '$': (void)sprintf (line+linelim, "\"%s\"", e->e.s);
- linelim += strlen(line+linelim);
- break;
-
- case REDUCE | '+': range_arg( "@sum(", e); break;
- case REDUCE | '*': range_arg( "@prod(", e); break;
- case REDUCE | 'a': range_arg( "@avg(", e); break;
- case REDUCE | 's': range_arg( "@stddev(", e); break;
- case REDUCE | MAX: range_arg( "@max(", e); break;
- case REDUCE | MIN: range_arg( "@min(", e); break;
-
- case ACOS: one_arg( "@acos(", e); break;
- case ASIN: one_arg( "@asin(", e); break;
- case ATAN: one_arg( "@atan(", e); break;
- case ATAN2: two_arg( "@atan2(", e); break;
- case CEIL: one_arg( "@ceil(", e); break;
- case COS: one_arg( "@cos(", e); break;
- case EXP: one_arg( "@exp(", e); break;
- case FABS: one_arg( "@fabs(", e); break;
- case FLOOR: one_arg( "@floor(", e); break;
- case HYPOT: two_arg( "@hypot(", e); break;
- case LOG: one_arg( "@ln(", e); break;
- case LOG10: one_arg( "@log(", e); break;
- case POW: two_arg( "@pow(", e); break;
- case SIN: one_arg( "@sin(", e); break;
- case SQRT: one_arg( "@sqrt(", e); break;
- case TAN: one_arg( "@tan(", e); break;
- case DTR: one_arg( "@dtr(", e); break;
- case RTD: one_arg( "@rtd(", e); break;
- case RND: one_arg( "@rnd(", e); break;
- case HOUR: one_arg( "@hour(", e); break;
- case MINUTE: one_arg( "@minute(", e); break;
- case SECOND: one_arg( "@second(", e); break;
- case MONTH: one_arg( "@month(", e); break;
- case DAY: one_arg( "@day(", e); break;
- case YEAR: one_arg( "@year(", e); break;
- case DATE: one_arg( "@date(", e); break;
- case STON: one_arg( "@ston(", e); break;
- case FMT: two_arg( "@fmt(", e); break;
- case EQS: two_arg( "@eqs(", e); break;
- case NOW: for ( s = "@now"; line[linelim++] = *s++;);
- linelim--;
- break;
- case LMAX: list_arg("@max(", e); break;
- case LMIN: list_arg("@min(", e); break;
- case FV: three_arg("@fv(", e); break;
- case PV: three_arg("@pv(", e); break;
- case PMT: three_arg("@pmt(", e); break;
- case NVAL: two_arg("@nval(", e); break;
- case SVAL: two_arg("@sval(", e); break;
- case EXT: two_arg("@ext(", e); break;
- case SUBSTR: three_arg("@substr(", e); break;
- case STINDEX: index_arg("@stindex(", e); break;
- case INDEX: index_arg("@index(", e); break;
- case LOOKUP: index_arg("@lookup(", e); break;
-
- default: decompile (e->e.o.left, mypriority);
- line[linelim++] = e->op;
- decompile (e->e.o.right, mypriority+1);
- break;
-
- }
- if (mypriority<priority) line[linelim++] = ')';
- } else line[linelim++] = '?';
- }
-
- index_arg(s, e)
- char *s;
- struct enode *e;
- {
- for (; line[linelim++] = *s++;);
- linelim--;
- decompile( e-> e.o.left, 0 );
- range_arg(", ", e->e.o.right);
- }
-
- list_arg(s, e)
- char *s;
- struct enode *e;
- {
- for (; line[linelim++] = *s++;);
- linelim--;
-
- decompile (e->e.o.right, 0);
- line[linelim++] = ',';
- decompile_list(e->e.o.left);
- line[linelim - 1] = ')';
- }
-
- one_arg(s, e)
- char *s;
- struct enode *e;
- {
- for (; line[linelim++] = *s++;);
- linelim--;
- decompile (e->e.o.right, 0);
- line[linelim++] = ')';
- }
-
- two_arg(s,e)
- char *s;
- struct enode *e;
- {
- for (; line[linelim++] = *s++;);
- linelim--;
- decompile (e->e.o.left, 0);
- line[linelim++] = ',';
- decompile (e->e.o.right, 0);
- line[linelim++] = ')';
- }
-
- three_arg(s,e)
- char *s;
- struct enode *e;
- {
- for (; line[linelim++] = *s++;);
- linelim--;
- decompile (e->e.o.left, 0);
- line[linelim++] = ',';
- decompile (e->e.o.right->e.o.left, 0);
- line[linelim++] = ',';
- decompile (e->e.o.right->e.o.right, 0);
- line[linelim++] = ')';
- }
-
- range_arg(s,e)
- char *s;
- struct enode *e;
- {
- struct range *r;
-
- for (; line[linelim++] = *s++;);
- linelim--;
- if (r = find_range((char *)0, 0, e->e.r.left.vp,
- e->e.r.right.vp)) {
- (void)sprintf(line+linelim, "%s", r->r_name);
- linelim += strlen(line+linelim);
- } else {
- decodev (e->e.r.left);
- line[linelim++] = ':';
- decodev (e->e.r.right);
- }
- line[linelim++] = ')';
- }
-
- editv (row, col)
- int row, col;
- {
- register struct ent *p;
-
- p = lookat (row, col);
- (void)sprintf (line, "let %s = ", v_name(row, col));
- linelim = strlen(line);
- if (p->flags & is_strexpr || p->expr == 0) {
- (void)sprintf (line+linelim, "%.15g", p->v);
- linelim += strlen (line+linelim);
- } else {
- editexp(row,col);
- }
- }
-
- editexp(row,col)
- int row, col;
- {
- register struct ent *p;
-
- p = lookat (row, col);
- decompile (p->expr, 0);
- line[linelim] = 0;
- }
-
- edits (row, col)
- int row, col;
- {
- register struct ent *p;
-
- p = lookat (row, col);
- (void)sprintf (line, "%sstring %s = ",
- ((p->flags&is_leftflush) ? "left" : "right"),
- v_name(row, col));
- linelim = strlen(line);
- if (p->flags & is_strexpr && p->expr) {
- editexp(row, col);
- } else if (p->label) {
- (void)sprintf (line+linelim, "\"%s\"", p->label);
- linelim += strlen (line+linelim);
- } else {
- (void)sprintf (line+linelim, "\"");
- linelim += 1;
- }
- }
- \SHAR\EOF\
- else
- echo "will not over write ./interp.c"
- fi
- if [ `wc -c ./interp.c | awk '{printf $1}'` -ne 40555 ]
- then
- echo `wc -c ./interp.c | awk '{print "Got " $1 ", Expected " 40555}'`
- fi
- if `test ! -s ./crypt.c`
- then
- echo "Extracting ./crypt.c"
- cat > ./crypt.c << '\SHAR\EOF\'
- /*
- * Encryption utilites
- * Bradley Williams
- * {allegra,ihnp4,uiucdcs,ctvax}!convex!williams
- * $Revision: 6.1 $
- */
-
- #include <stdio.h>
- #include <curses.h>
-
- #if defined(BSD42) || defined(BSD43)
- #include <sys/file.h>
- #else
- #include <fcntl.h>
- #endif
-
- #include "sc.h"
-
- char *strcpy();
-
- #ifdef SYSV3
- void exit();
- #endif
-
- int Crypt = 0;
-
- creadfile (save, eraseflg)
- char *save;
- int eraseflg;
- {
- register FILE *f;
- int pipefd[2];
- int fildes;
- int pid;
-
- if (eraseflg && strcmp(save, curfile) && modcheck(" first")) return;
-
- fildes = open (save, O_RDONLY, 0);
- if (fildes < 0)
- {
- error ("Can't read file \"%s\"", save);
- return;
- }
-
- if (eraseflg) erasedb ();
-
- if (pipe(pipefd) < 0) {
- error("Can't make pipe to child");
- return;
- }
-
- deraw();
- if ((pid=fork()) == 0) /* if child */
- {
- (void) close (0); /* close stdin */
- (void) close (1); /* close stdout */
- (void) close (pipefd[0]); /* close pipe input */
- (void) dup (fildes); /* standard in from file */
- (void) dup (pipefd[1]); /* connect to pipe */
- (void) fprintf (stderr, " ");
- (void) execl ("/bin/sh", "sh", "-c", "crypt", 0);
- exit (-127);
- }
- else /* else parent */
- {
- (void) close (fildes);
- (void) close (pipefd[1]); /* close pipe output */
- f = fdopen (pipefd[0], "r");
- if (f == 0)
- {
- (void) kill (pid, -9);
- error ("Can't fdopen file \"%s\"", save);
- (void) close (pipefd[0]);
- return;
- }
- }
-
- loading++;
- while (fgets(line,sizeof line,f)) {
- linelim = 0;
- if (line[0] != '#') (void) yyparse ();
- }
- --loading;
- (void) fclose (f);
- (void) close (pipefd[0]);
- while (pid != wait(&fildes)) /**/;
- goraw();
- linelim = -1;
- modflg++;
- if (eraseflg) {
- (void) strcpy (curfile, save);
- modflg = 0;
- }
- EvalAll();
- }
-
- cwritefile (fname, r0, c0, rn, cn)
- char *fname;
- int r0, c0, rn, cn;
- {
- register FILE *f;
- int pipefd[2];
- int fildes;
- int pid;
- char save[1024];
- char *fn;
-
-
- if (*fname == 0) fname = &curfile[0];
-
- fn = fname;
- while (*fn && (*fn == ' ')) /* Skip leading blanks */
- fn++;
-
- if ( *fn == '|' ) {
- error ("Can't have encrypted pipe");
- return(-1);
- }
-
- (void) strcpy(save,fname);
-
- fildes = open (save, O_WRONLY|O_CREAT, 0600);
- if (fildes < 0)
- {
- error ("Can't create file \"%s\"", save);
- return(-1);
- }
-
- if (pipe (pipefd) < 0) {
- error ("Can't make pipe to child\n");
- return(-1);
- }
-
- deraw();
- if ((pid=fork()) == 0) /* if child */
- {
- (void) close (0); /* close stdin */
- (void) close (1); /* close stdout */
- (void) close (pipefd[1]); /* close pipe output */
- (void) dup (pipefd[0]); /* connect to pipe input */
- (void) dup (fildes); /* standard out to file */
- (void) fprintf (stderr, " ");
- (void) execl ("/bin/sh", "sh", "-c", "crypt", 0);
- exit (-127);
- }
- else /* else parent */
- {
- (void) close (fildes);
- (void) close (pipefd[0]); /* close pipe input */
- f = fdopen (pipefd[1], "w");
- if (f == 0)
- {
- (void) kill (pid, -9);
- error ("Can't fdopen file \"%s\"", save);
- (void) close (pipefd[1]);
- return(-1);
- }
- }
-
- write_fd(f, r0, c0, rn, cn);
-
- (void) fclose (f);
- (void) close (pipefd[1]);
- while (pid != wait(&fildes)) /**/;
- (void) strcpy(curfile,save);
-
- modflg = 0;
- error ("File \"%s\" written", curfile);
- goraw();
- return(0);
- }
-
- \SHAR\EOF\
- else
- echo "will not over write ./crypt.c"
- fi
- if [ `wc -c ./crypt.c | awk '{printf $1}'` -ne 3437 ]
- then
- echo `wc -c ./crypt.c | awk '{print "Got " $1 ", Expected " 3437}'`
- fi
- echo "Finished archive 3 of 4"
- # if you want to concatenate archives, remove anything after this line
- exit
-
-